/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frreport_mng.c                                     */
/*  NOTE      = 上报数据模块                                       */
/*  DATE      = 2014/11/20                                         */
/*******************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#include <zmq.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frhash2.h"

#include "module.h"
#include "frame_params.h"
#include "frct_mng.h"
#include "frreport_mng.h"
#include "frreport_convert.h"
#include "frreport_comm.h"

#if defined(FRDBG_REPORT_TESTTOOLS) || defined(FRDBG_REPORT_FILE) || defined(FRDBG_REPORT_SHOW)
#include "frreport_dbg.h"
#endif

//zeromq 连接用信息
static void *p_st_zmq_context = NULL;
static void *p_st_zmq_sender=NULL;

/*******************************************************************************
*  FUNC     :  节点data_field内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
static void __list_node_free_data_field(Frlist_node *p_st_node)
{
    Frdata_field *p_st_data_field;

    if(p_st_node==NULL || p_st_node->data == NULL )
        return;

    p_st_data_field = (Frdata_field *)FRLIST_GET_NODE_DATA(p_st_node);

    if(p_st_data_field->p_field_name)
        frfree(p_st_data_field->p_field_name);
    if(p_st_data_field->p_field_value)
        frfree(p_st_data_field->p_field_value);
    frfree(p_st_node->data);

    return;
}

/*******************************************************************************
*  FUNC     :  节点data_field内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
static void __list_node_free_l7data_field(Frlist_node *p_st_node)
{
    FRl7data_field *p_st_l7data_field=NULL;

    if(p_st_node==NULL || p_st_node->data == NULL )
        return;

    p_st_l7data_field = (FRl7data_field *)FRLIST_GET_NODE_DATA(p_st_node);
    frreport_free_l7data_field(&p_st_l7data_field);

    //frfree(p_st_node->data);
    return;
}

/*******************************************************************************
*  FUNC     :  Frreport_data内存释放
*  ARGS     :  p_st_report_data  (Frreport_data *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frreport_free_report_data(Frreport_data *p_st_report_data)
{

    if(p_st_report_data == NULL)
        return;

    //连接信息没有申请内存
    if(p_st_report_data->em_data_type == FRREPORT_TYPE_CONN
       || p_st_report_data->em_data_type == FRREPORT_TYPE_CONN_EXPECT)
        return;

    //session数据释放
    if(p_st_report_data->em_data_type == FRREPORT_TYPE_SESSION)
    {
        Frreport_session *p_st_session=NULL;
        p_st_session = &p_st_report_data->un_data.st_session;
        if(p_st_session->p_username)
        {
            frfree(p_st_session->p_username);
            p_st_session->p_username = NULL;
        }
        if(p_st_report_data->un_data.st_session.p_st_lst_session_data)
        {
            frlist_destroy(p_st_report_data->un_data.st_session.p_st_lst_session_data, __list_node_free_data_field);
            p_st_report_data->un_data.st_session.p_st_lst_session_data = NULL;
        }
        return;
    }

    //l7数据释放
    if(p_st_report_data->em_data_type == FRREPORT_TYPE_DATA)
    {
        Frreport_l7data  *p_st_l7data=NULL;
        p_st_l7data = &p_st_report_data->un_data.st_l7data;
        if(p_st_l7data->p_transaction_code)
        {
            frfree(p_st_l7data->p_transaction_code);
            p_st_l7data->p_transaction_code = NULL;
        }
        if(p_st_l7data->p_transaction_title)
        {
            frfree(p_st_l7data->p_transaction_title);
            p_st_l7data->p_transaction_title = NULL;
        }
        if(p_st_l7data->p_response_codestring)
        {
            frfree(p_st_l7data->p_response_codestring);
            p_st_l7data->p_response_codestring = NULL;
        }
        frlist_remove_all(&p_st_l7data->st_lst_l7data, __list_node_free_l7data_field);
        frlist_header_init(&p_st_l7data->st_lst_l7data);

        return;
    }

    return;
}

/*******************************************************************************
*  FUNC     :  初始化zeromq连接
*  ARGS     :
*  RTN      :  成功:FR_SUCC; 失败:FR_FAIL
*  NOTE     :
*******************************************************************************/
int frreport_mng_conn_init(void)
{
    int i_ret_fun=0;

    #ifdef FRDBG_NO_ZMQ_SEND
        return FR_SUCC;
    #endif

    p_st_zmq_context = zmq_init(1);
    p_st_zmq_sender = zmq_socket(p_st_zmq_context,ZMQ_PUSH);

    if(p_st_zmq_context == NULL || p_st_zmq_sender == NULL)
    {
        FRLOG_ERROR_DETAIL("zmq_init err");
        return FR_FAIL;
    }

    i_ret_fun = zmq_connect(p_st_zmq_sender, st_apm_params.arr_zmq_connect);
    if(i_ret_fun == 0)
        return FR_SUCC;

    //出错
    if(p_st_zmq_sender)
    {
        zmq_close(p_st_zmq_sender);
        p_st_zmq_sender = NULL;
    }
    if(p_st_zmq_context)
    {
        //zmq_ctx_destroy(p_st_zmq_context);
        zmq_term(p_st_zmq_context);
        p_st_zmq_context = NULL;
    }
    FRLOG_ERROR_DETAIL("zmq_connect err connects[%s]", st_apm_params.arr_zmq_connect);
    return FR_FAIL;

}

/*******************************************************************************
*  FUNC     :  释放zeromq连接
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frreport_mng_conn_destory(void)
{
#ifdef FRDBG_NO_ZMQ_SEND
    return;
#endif

    if(p_st_zmq_sender)
    {
        int i_zero=0;
        //有尚未发送消息也退出
        zmq_setsockopt(p_st_zmq_sender, ZMQ_LINGER, &i_zero, sizeof(int));
        zmq_close(p_st_zmq_sender);
        p_st_zmq_sender = NULL;
    }
    if(p_st_zmq_context)
    {
        //zmq_ctx_destroy(p_st_zmq_context);
        zmq_term(p_st_zmq_context);
        p_st_zmq_context = NULL;
    }

    return;
}

/*******************************************************************************
*  FUNC     :  Frreport_data数据上报
*  ARGS     :  p_st_report_data (Frreport_data *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frreport_mng_send_report_data(Frreport_data *p_st_report_data)
{
#ifndef FRDBG_NO_ZMQ_SEND
    char *p_convert_data=NULL;
    unsigned int ui_len=0;
    int i_ret_fun=0;
#endif

    if(p_st_report_data == NULL)
        return;

    //调试用数据出力
    #if defined(FRDBG_REPORT_TESTTOOLS) || defined(FRDBG_REPORT_FILE) || defined(FRDBG_REPORT_SHOW)
    {
        char *p_show_data=NULL;
        unsigned int ui_show_data_len=0;
        frdbg_report_data_format(p_st_report_data, &p_show_data, &ui_show_data_len);
        if(p_show_data)
        {
            #ifdef FRDBG_REPORT_SHOW
            frdbg("\n[%s]\n", p_show_data);
            #endif

            if(ui_show_data_len > 1)
            {
                #ifdef FRDBG_REPORT_FILE
                frdbg_report_data_write(st_apm_params.arr_apmdbg_report_file, p_show_data, ui_show_data_len-1);
                #endif

                #ifdef FRDBG_REPORT_TESTTOOLS
                frdbg_report_data_send_tcp(st_apm_params.arr_apmdbg_report_ip, st_apm_params.ui_apmdbg_report_port , p_show_data, ui_show_data_len-1);
                #endif
            }

            frfree(p_show_data);
        }
    }
    #endif

    //数据转换并上报
    #ifndef FRDBG_NO_ZMQ_SEND
    i_ret_fun = frreport_convert(p_st_report_data, &p_convert_data, &ui_len);
    if(p_convert_data != NULL)
    {
        zmq_send(p_st_zmq_sender, p_convert_data, ui_len, 0);
        frfree(p_convert_data);
    }
    #endif

    return;
}

/*******************************************************************************
*  FUNC     :  发送connect
*  ARGS     :  p_st_ct      (Conntrack *)
*           :  i_status     (连接状态: APM_CONNECT_SYN_SENT / APM_CONNECT_SYN_RECV / APM_CONNECT_ESTABLISHED / APM_CONNECT_CLOSED / APM_CONNECT_TIMEOUT)
*           :  st_timeval   (数据包发生时间)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frreport_mng_send_conn(Conntrack *p_st_ct, int i_status, struct timeval st_timeval)
{
    Frreport_data st_report_data;
    Frreport_conn *p_st_conn=NULL;
#ifndef FRDBG_NO_ZMQ_SEND
    char *p_convert_data=NULL;
    unsigned int ui_len=0;
    int i_ret_fun=0;
#endif

    if(p_st_ct == NULL)
        return;

    //组织数据
    memset(&st_report_data, 0x00, sizeof(Frreport_data));
    st_report_data.em_data_type = FRREPORT_TYPE_CONN;
    p_st_conn = &st_report_data.un_data.st_conn;

    memcpy(p_st_conn->arr_connection_id, p_st_ct->arr_connection_id, APM_UUID_SIZE);
    p_st_conn->ip_proto = p_st_ct->ip_proto;
    memcpy(p_st_conn->src_mac, p_st_ct->src_mac, APM_MAC_SIZE);
    p_st_conn->src_ip = p_st_ct->src_ip;
    p_st_conn->src_port = p_st_ct->src_port;
    p_st_conn->dst_ip = p_st_ct->dst_ip;
    p_st_conn->dst_port = p_st_ct->dst_port;

    /*
        CONNECTING = 1;  //TCP syn包发出后发送connecting消息
        ESTABLISHED = 2; //TCP三次握手后或UDP连接建立时发送established消息
        DISCONNECT = 3; //TCP收到fin包后发送disconnect消息
        DESTROY = 4; //连接被强制销毁时发送destroy消息
        DATA_TIMEOUT = 5; //连接30分钟内未没有任何数据包时发送data_timeout消息
    */
    if(i_status == APM_CONNECT_SYN_SENT || i_status==APM_CONNECT_SYN_RECV )
        p_st_conn->i_event = 1;
    else if(i_status == APM_CONNECT_ESTABLISHED)
        p_st_conn->i_event = 2;
    else if(i_status == APM_CONNECT_CLOSED)
            p_st_conn->i_event = 3;
    else if(i_status == APM_CONNECT_TIMEOUT)
        p_st_conn->i_event = 5;
    else
        p_st_conn->i_event = 4;

    p_st_conn->st_timestamp = st_timeval;

    //调试用数据出力
    #if defined(FRDBG_REPORT_TESTTOOLS) || defined(FRDBG_REPORT_FILE) || defined(FRDBG_REPORT_SHOW)
    {
        char *p_show_data=NULL;
        unsigned int ui_show_data_len=0;
        frdbg_report_data_format(&st_report_data, &p_show_data, &ui_show_data_len);
        if(p_show_data)
        {
            #ifdef FRDBG_REPORT_SHOW
            frdbg("\n[%s]\n", p_show_data);
            #endif

            if(ui_show_data_len > 1)
            {
                #ifdef FRDBG_REPORT_FILE
                frdbg_report_data_write(st_apm_params.arr_apmdbg_report_file, p_show_data, ui_show_data_len-1);
                #endif

                #ifdef FRDBG_REPORT_TESTTOOLS
                frdbg_report_data_send_tcp(st_apm_params.arr_apmdbg_report_ip, st_apm_params.ui_apmdbg_report_port , p_show_data, ui_show_data_len-1);
                #endif
            }


            frfree(p_show_data);
        }
    }
    #endif

    #ifndef FRDBG_NO_ZMQ_SEND
    p_convert_data = NULL;
    ui_len = 0;
    i_ret_fun = frreport_convert(&st_report_data, &p_convert_data, &ui_len);
    if(p_convert_data != NULL)
    {
        if(ui_len > 0)
        {
            //数据上报
            zmq_send(p_st_zmq_sender, p_convert_data, ui_len, 0);
        }
        frfree(p_convert_data);
    }
    #endif

    return;
}

